package com.inspur.edp.common.expr.ast;


import com.inspur.edp.common.expr.exception.ExpressException;
import com.inspur.edp.common.type.Type;
import com.inspur.edp.common.type.TypeRefer;
import com.inspur.edp.common.type.cache.TypeThreadCache;
import com.inspur.edp.common.type.utils.TypeUtil;

import java.util.*;

/**
 * @author lizhaorui
 * @description TODO
 * @date 2025/4/9 9:28
 */
public abstract class AbsASTContext implements ASTContext {

    private Map<String, String> importMap = new HashMap<>();

    private VariableScope varContext = new VariableScope();

    private List<String> methods = new ArrayList<>();

    private List<String> genericTypeNames;

    @Override
    public List<String> getGenericTypeNames() {
        if (this.genericTypeNames == null) {
            this.genericTypeNames = new ArrayList<>();
        }
        return genericTypeNames;
    }


    public void beginVarScope(boolean isolate) {
        this.varContext.beginVarScope(isolate);
    }

    public void commitVarScope() {
        this.varContext.commitVarScope();
    }


    @Override
    public Type getType(String url) {
        return TypeThreadCache.getByUrl(url);
    }

    @Override
    public Type getType(TypeRefer typeRefer) {
        return TypeThreadCache.getType(typeRefer);
    }

    public void addImport(TypeRefer refer) {
        List<TypeRefer> imports = refer.getImportTypes();
        for (TypeRefer importTypeRefer : imports) {
            Type importType = TypeThreadCache.getType(importTypeRefer);
            String typeUrl = TypeUtil.getTypeUrl(importType);
            this.addImport(typeUrl);
        }
    }

    @Override
    public void addImport(String fullName) {
        int index = fullName.lastIndexOf(".");
        if (index < 0) {
            char firstChar = fullName.charAt(0);
            if (Character.isLowerCase(firstChar)) {
                return;
            }
        }
        String className = TypeUtil.getTypeCode(fullName);
        this.importMap.put(className, fullName);
    }

    @Override
    public void addImports(Collection<String> imports) {
        imports.forEach(this::addImport);
    }

    public Collection<String> getAllImports() {
        List<String> allImports = new ArrayList<>();
        if (this.importMap != null) {
            for (Map.Entry<String, String> entry : this.importMap.entrySet()) {
                allImports.add(entry.getValue());
            }
        }
        return allImports;
    }

    public void setAllImports(Collection<String> imports) {
        this.importMap = new HashMap<>();
        this.addImports(imports);
    }

    @Override
    public boolean containImportName(String typeName) {
        return this.importMap.containsKey(typeName);
    }

    @Override
    public String getImportFullName(String typeName) {
        if (this.importMap.containsKey(typeName)) {
            return this.importMap.get(typeName);
        }
        throw new ExpressException("import do not contain [" + typeName + "]");
    }

    @Override
    public void addVariable(String varName, TypeRefer typeRefer) {
        this.varContext.addVarType(varName, typeRefer);
    }

    @Override
    public void removeVariable(String varName) {
        this.varContext.removeVar(varName);
    }

    @Override
    public TypeRefer getVarType(String varName) {
        return this.varContext.getVarType(varName);
    }

    @Override
    public boolean containVarName(String varName) {
        return this.varContext.containVarName(varName);
    }

    public String getImportDSL() {
        StringBuilder sb = new StringBuilder();
        for (String importKey : importMap.keySet()) {
            sb.append(String.format("\nimport {%s} from \"%s\";", importKey, importMap.get(importKey)));
        }
        return sb.toString();
    }

    public List<String> getMethods() {
        return methods;
    }

    public void setMethods(List<String> methods) {
        this.methods = methods;
    }

}
